﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using Vowei.Data.Models;
using Vowei.Core.Models;
using System.Data.Objects;
using System.Data.Entity.Infrastructure;
using System.Diagnostics;
using Vowei.Data.Helpers;
using Vowei.Core;

namespace Vowei.Data
{
    public class VoweiContext : DbContext
    {
        private static object[] EmptyParams = new object[] { };

        private static Dictionary<Type, string> TableMap { get; set; }

        static VoweiContext()
        {
            TableMap = new Dictionary<Type, string>();
            TableMap.Add(typeof(Ticket), "Tickets");
            TableMap.Add(typeof(Task), "Tasks");
            //TableMap.Add(typeof(MeetingRequest), "MeetingRequests");
            //TableMap.Add(typeof(Bug), "Bugs");
            //TableMap.Add(typeof(Tag), "Tags");
            TableMap.Add(typeof(Risk), "Risks");
            //TableMap.Add(typeof(CategoryColor), "CategoryColors");
            TableMap.Add(typeof(Project), "Projects");
            TableMap.Add(typeof(Milestone), "Milestones");
            TableMap.Add(typeof(Requirement), "Requirements");
            TableMap.Add(typeof(Comment), "Comments");
            TableMap.Add(typeof(ITicket), "Tickets");
            TableMap.Add(typeof(ITask), "Tasks");
            TableMap.Add(typeof(ITag), "Tags");
            TableMap.Add(typeof(IRisk), "Risks");
            TableMap.Add(typeof(IProject), "Projects");
            TableMap.Add(typeof(IMilestone), "Milestones");
            TableMap.Add(typeof(IRequirement), "Requirements");
            TableMap.Add(typeof(IComment), "Comments");
        }

        public VoweiContext()
            : base("name=Entities")
        {
        }

        public ObjectContext QuerableContext { get { return ((IObjectContextAdapter)this).ObjectContext; } }

        public DbSet<Ticket> Tickets { get; set; }

        public DbSet<Task> Tasks { get; set; }

        //public DbSet<MeetingRequest> MeetingRequests { get; set; }

        public DbSet<Bug> Bugs { get; set; }

        public DbSet<Risk> Risks { get; set; }
        
        public DbSet<Project> Projects { get; set; }

        public DbSet<Milestone> Milestones { get; set; }

        public DbSet<Requirement> Requirements { get; set; }

        public DbSet<Comment> Comments { get; set; }

        //public DbSet<Tag> Tags { get; set; }

        public DbSet<ChangeSet> ChangeSets { get; set; }

        public DbSet<Permission> Permissions { get; set; }

        public DbSet<PermissionSet> PermissionSet { get; set; }

        public DbSet<Ace> Acl { get; set; }

        // TODO: 任务的状态信息应该要转换成一个数据表，这个数据表允许客户自定义项目的任务状态
        private IQueryable<string> _TicketStatus = new string[] {
            "Not Started",
            "In Progress",
            "Completed",
            "Deferred",
            "Waiting on someone else"
        }.AsQueryable();
        public IQueryable<string> TicketStatus
        {
            get { return _TicketStatus; }
        }

        public DbSet<T> FindTableByType<T>()
            where T : class
        {
            if (!TableMap.ContainsKey(typeof(T)))
                throw new InvalidOperationException(string.Format("类型 {0} 并没有相关的表对应!", typeof(T)));

            var propertyInfo = typeof(VoweiContext).GetProperty(VoweiContext.TableMap[typeof(T)]);
            Debug.Assert(propertyInfo != null);
            var propertyValue = propertyInfo.GetValue(this, EmptyParams);
            return (DbSet<T>)propertyValue;
        }

        /// <summary>
        /// 根据ID从数据库中查找某个类型的实例
        /// </summary>
        /// <typeparam name="T">需要查询的数据类型，比如任务、项目等</typeparam>
        /// <param name="id">数据的主键</param>
        /// <returns>数据的实例</returns>
        public T Find<T>(Guid id) where T : class
        {
            var table = FindTableByType<T>();

            return table.Find(id);
        }

        public T Create<T>(string title)
            where T : class, INamedTable, ISupportDefaultProperties, new()
        {
            var item = new T() { Title = title };
            item.OpenDate = DateTime.Now;
            item.Reporter = Constants.BuiltIn.Users.Active;

            return item;
        }

        public IQueryable<Requirement> LoadRequirements(Milestone milestone)
        {
            return milestone.AllTickets(this).OfType<Requirement>();
        }

        public IQueryable<Task> LoadTasks(Requirement root)
        {
            return root.AllTickets(this).OfType<Task>();
        }

        public IQueryable<Task> LoadTasks(Milestone milestone)
        {
            return milestone.AllTickets(this).OfType<Task>();
        }

        public IQueryable<Milestone> UnAssignedMilestone()
        {
            return Milestones.Where(m => (m.Parent == null) && !(m is Milestone));
        }

        public Project FindProjectFor(Ticket ticket)
        {
            var nodes = ticket.Ancestors(this);
            if (nodes.Length == 0)
            {
                throw new ArgumentException(
                    string.Format("找不到任务ID: {0}在系统中的里程碑节点层次信息", ticket.ID));
            }

            var pnode = nodes[nodes.Length - 1];

            var project = Projects.Find(pnode.ID);
            if (project == null)
            {
                throw new InvalidOperationException(
                    string.Format("任务:{0}在系统中保存了与里程碑或需求的层次关系，但是找不到对应的里程碑信息", ticket.ID));
            }

            return project;
        }

        public void ImportProjectData(Guid pid, IEnumerable<ITable> items)
        {
            var project = Projects.Find(pid);
            if (project == null)
                throw new InvalidOperationException(string.Format("找不到id为{0}的项目", pid));

            foreach (var milestone in items.OfType<IMilestone>())
            {
                if (milestone.Parent == null)
                    project.AddChild(milestone);
            }

            foreach (var requirement in items.OfType<IRequirement>())
                Requirements.Add((Requirement)requirement);

            foreach (var task in items.OfType<ITask>())
                Tasks.Add((Task)task);

            try
            {
                SaveChanges();
            }
            catch (System.Data.Entity.Validation.DbEntityValidationException e)
            {
                foreach (var error in e.EntityValidationErrors)
                {
                    Trace.WriteLine(string.Format("[VoweiContext.ImportProjectData]: {0}, Error details: \n _____________________",
                        ((INamedTable)error.Entry.Entity).Title));

                    foreach (var de in error.ValidationErrors)
                        Trace.WriteLine(string.Format("属性: {0} -> {1}", de.PropertyName, de.ErrorMessage));
                }

                throw e;
            }
        }
    }
}
